﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Communication.Net.Telnet;
using UtilZ.Dotnet.Ex.Communication.Net.Web;
using UtilZ.Dotnet.Ex.Json;
using UtilZ.Dotnet.Ex.Log;
using UtilZ.Dotnet.Ex.Model;

namespace ConAppCore
{
    internal class TestHttpServer
    {
        public static void Test()
        {
            //StartTelnetServer();

            //var webSiteConfig = new WebSiteConfig(@"D:\SelfCode\UtilZ\UtilZ.Tool.Host\App\UtilZ.Tool.HostAgent\bin\Debug\net7.0\Log", @"D:\SelfCode\UtilZ\UtilZ.Tool.Host\Plugins\UtilZ.Tool.WatchdogPlugin\htmls\watchdog.html");

            TestServer();
            //TestCallApi();
        }



        #region telnet 

        private static TelnetServer _telnetServer = null;

        private static void StartTelnetServer()
        {
            int port = 23;
            var config = new TelnetConfig();
            //config.Users = new TelnetUserInfo[]
            //{
            //    new TelnetUserInfo("yf","yf")
            //};
            _telnetServer = new TelnetServer(ProcessTelnetMessage, config);
            _telnetServer.ConnectedPromptMessage = "<<<XX服务>>>";
            _telnetServer.Start();
            Loger.Info($"TelnetServer started.端口{port}..");
        }


        private static string ProcessTelnetMessage(TelnetMessageArgs args)
        {
            try
            {

                //var message = args.Message;
                //if (string.IsNullOrWhiteSpace(message))
                //{
                //    return string.Empty;
                //}

                //message = message.ToLower().Trim();

                var client = _webSocketList.FirstOrDefault();
                if (client != null)
                {
                    using (var ms = new MemoryStream())
                    {
                        var bw = new BinaryWriter(ms);
                        bw.Write((Int32)101);

                        byte[] content = Encoding.UTF8.GetBytes("夜风yf123");
                        bw.Write(content.Length);
                        bw.Write(content, 0, content.Length);
                        ms.Flush();
                        byte[] buffer = ms.GetBuffer().Take((int)ms.Length).ToArray();

                        //向websocket客户端发送二进制数据
                        client.Send(buffer);
                    }
                }

                return "ok";
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
                return ex.ToString();
            }
        }

        #endregion


        #region TestServer
        private static void TestServer()
        {
            //GetTemplatePara();
            //UpdateContentType();
            //TestHttpRequestRange();

            try
            {
                var handler = new HttpRequestHandler();

                //handler.AddMiddleware(new TestRequestMiddleware(), 0);

                var websocketMiddleware = new WebsocketMiddleware(ValidateWebsocket, OutputWebsocket);
                handler.AddMiddleware(websocketMiddleware, 200);

                var smm = new SessionManagerMiddleware();
                handler.AddMiddleware(smm, 8);

                var apiMiddleware = new ApiMiddleware(new TestSerializer());
                apiMiddleware.AddApi(new TestApi(smm));
                apiMiddleware.AddApi(new GISTileFileApi());
                //apiMiddleware.AddApi(new TestDynamicApi());
                apiMiddleware.AddApi(new DynamicTileApi());


                apiMiddleware.MapGet("/getPersons?min={min}&max={max}", new Func<int, int, string>((min, max) =>
                {
                    return $"{DateTime.Now}_{min}_{max}";
                }));




                handler.AddMiddleware(apiMiddleware, 10);
                string apiInfo = apiMiddleware.GetAllApiList();

                var appDir = PathEx.GetTypeAssemblyDirectory(typeof(TestHttpServer));
                DirectoryInfo dirInfo = new DirectoryInfo(appDir);
                string rootDir = Path.Combine(dirInfo.Parent.Parent.Parent.FullName, "htmls");
                //rootDir = @"D:\SelfCode\UtilZ.DotnetEx\Test\ConAppCore\htmls";
                string[] sourceDirs = new string[] { @"D:\Media", @"D:\Soft", @"F:\Movie", @"E:\Soft",@"E:\Code\ZHN\UtilZ.DotnetEx\Test\ConAppCore\bin\Debug\net6.0\imgs",
                    @"E:\Code\ZHN\UtilZ.DotnetEx\Test\BlazorAssemblyApp\bin\Release\net6.0\browser-wasm\publish\wwwroot",
                @"E:\Code\Demo\2022-1-6\AvaloniaApplication1\bin\Release\net6.0\publish"};
                var webSiteConfig = new WebSiteConfig(rootDir, "httpserver-test.html", sourceDirs);
                webSiteConfig.ResourceProvider = new WebSiteFileProvider();
                handler.AddMiddleware(new WebSiteMiddleware(webSiteConfig), 100);


                var config = new HttpServerConfig();
                config.MaxConnections = 4;
                config.ListenEndPoint = new IPEndPoint(IPAddress.Any, 8080);
                HttpServer httpServer = new HttpServer(config, handler);
                httpServer.Start();
                Loger.Info("http server 启动完成");
                Loger.Info("q exit");

                ConsoleKeyInfo consoleKey;
                while (true)
                {
                    consoleKey = Console.ReadKey();
                    if (consoleKey.Key == ConsoleKey.Q)
                    {
                        break;
                    }
                }
                httpServer.Dispose();
            }
            catch (Exception ex)
            {
                Loger.Fatal(ex);
            }
        }

        private static void GetTemplatePara()
        {
            /******************************************************
             * FixUrl               http://api/v1/fix       (固定模板或模板为空皆为固定url)
             * QueryStringPara      http://192.168.10.96:23018/testApi/qsp?min={timestampMin}&max={timestampMax}
             * UrlPara              http://192.168.10.96:23018/testApi/url/{z}/gg{x}mm/kk/{y}.png
             * Mix                  http://192.168.10.96:23018/testApi/mid/{z}/gg{x}mm/kk/{y}.png?min={timestampMin}&max={timestampMax}
             ******************************************************/

            PrimitiveGetTemplatePara(@"http://192.168.10.96:23018/testApi/mid/{z}/gg{x}mm/kk/{y}.png?min={timestampMin}&max={timestampMax}");

            //PrimitiveGetTemplatePara(@"http://api/v1/fix");
            //PrimitiveGetTemplatePara(@"http://192.168.10.96:23018/testApi/qsp?min={timestampMin}&max={timestampMax}");
            //PrimitiveGetTemplatePara(@"http://192.168.10.96:23018/testApi/url/{z}/gg{x}mm/kk/{y}.png");
            //PrimitiveGetTemplatePara(@"http://192.168.10.96:23018/testApi/mid/{z}/gg{x}mm/kk/{y}.png?min={timestampMin}&max={timestampMax}");
        }

        private static void PrimitiveGetTemplatePara(string template)
        {
            string regStr = @"";
            Match match = Regex.Match(template, regStr);
        }


        private static List<WebSocketClient> _webSocketList = new List<WebSocketClient>();
        private static bool ValidateWebsocket(HttpRequest request)
        {
            return true;
        }

        private static void OutputWebsocket(WebSocketClient webSocket)
        {
            webSocket.MessageOutput += WebSocket_MessageOutput;
            webSocket.ConnectionChanged += WebSocket_ConnectionChanged;
            _webSocketList.Add(webSocket);
            webSocket.StartReceive();
            Loger.Warn("WebSocket 建立");
        }

        private static void WebSocket_MessageOutput(object sender, MessageOutputArgs e)
        {
            try
            {
                var msg = e.Message;
                switch (msg.MessageType)
                {
                    case WebSocketMessageTypes.Text:
                        Loger.Info(((WebSocketTextMessage)msg).Text);
                        var client = (WebSocketClient)sender!;
                        //string filePath = @"D:\Projects\Posture\功能指标.txt";
                        //filePath = @"D:\1867.txt";
                        //filePath = @"D:\tmp\google-earth-dbroot-parser.js";
                        //string text = File.ReadAllText(filePath);
                        string text = $"WebSocket建立{TimeEx.GetTimestamp()}";
                        client.Send(text);

                        ////client.Send($"WebSocket建立{TimeEx.GetTimestamp()}");

                        ////client.Ping();

                        //byte[] data = new byte[] { 1, 2, 3, 4, 5, 6 };
                        //client.Send(data);
                        break;
                    case WebSocketMessageTypes.Binary:
                        Loger.Info("收到二进制消息");
                        break;
                    default:
                        Loger.Info($"收到{msg.MessageType.ToString()}消息");
                        break;
                }
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private static void WebSocket_ConnectionChanged(object sender, UtilZ.Dotnet.Ex.Communication.Net.Base.NetConnectedChangedArgs e)
        {
            var webSocket = (WebSocketClient)sender!;
            _webSocketList.Remove(webSocket);
            webSocket.Dispose();
            Loger.Warn("WebSocket 断开");
        }



        private static void TestHttpRequestRange()
        {
            long totalLength = 501;

            var range1 = new HttpRequestRange("bytes", "100-200");
            var contentRange1 = range1.GetArea(totalLength);

            var range2 = new HttpRequestRange("bytes", "-200");
            var contentRange2 = range2.GetArea(totalLength);

            var range3 = new HttpRequestRange("bytes", "100-");
            var contentRange3 = range3.GetArea(totalLength);
        }


        private static void UpdateContentType()
        {
            var mimieDic = new Dictionary<string, string>();

            mimieDic.Add(".*", "application/octet-stream");
            mimieDic.Add("0.001", "application/x-001");
            mimieDic.Add("0.323", "text/h323");
            mimieDic.Add("0.907", "drawing/907");
            mimieDic.Add(".acp", "audio/x-mei-aac");
            mimieDic.Add(".aif", "audio/aiff");
            mimieDic.Add(".aiff", "audio/aiff");
            mimieDic.Add(".asa", "text/asa");
            mimieDic.Add(".asp", "text/asp");
            mimieDic.Add(".au", "audio/basic");
            mimieDic.Add(".awf", "application/vnd.adobe.workflow");
            mimieDic.Add(".bmp", "application/x-bmp");
            mimieDic.Add(".c4t", "application/x-c4t");
            mimieDic.Add(".cal", "application/x-cals");
            mimieDic.Add(".cdf", "application/x-netcdf");
            mimieDic.Add(".cel", "application/x-cel");
            mimieDic.Add(".cg4", "application/x-g4");
            mimieDic.Add(".cit", "application/x-cit");
            mimieDic.Add(".cml", "text/xml");
            mimieDic.Add(".cmx", "application/x-cmx");
            mimieDic.Add(".crl", "application/pkix-crl");
            mimieDic.Add(".csi", "application/x-csi");
            mimieDic.Add(".cut", "application/x-cut");
            mimieDic.Add(".dbm", "application/x-dbm");
            mimieDic.Add(".dcd", "text/xml");
            mimieDic.Add(".der", "application/x-x509-ca-cert");
            mimieDic.Add(".dib", "application/x-dib");
            mimieDic.Add(".doc", "application/msword");
            mimieDic.Add(".drw", "application/x-drw");
            mimieDic.Add(".dwf", "Model/vnd.dwf");
            mimieDic.Add(".dwg", "application/x-dwg");
            mimieDic.Add(".dxf", "application/x-dxf");
            mimieDic.Add(".emf", "application/x-emf");
            mimieDic.Add(".ent", "text/xml");
            mimieDic.Add(".eps", "application/x-ps");
            mimieDic.Add(".etd", "application/x-ebx");
            mimieDic.Add(".fax", "image/fax");
            mimieDic.Add(".fif", "application/fractals");
            mimieDic.Add(".frm", "application/x-frm");
            mimieDic.Add(".gbr", "application/x-gbr");
            mimieDic.Add(".gif", "image/gif");
            mimieDic.Add(".gp4", "application/x-gp4");
            mimieDic.Add(".hmr", "application/x-hmr");
            mimieDic.Add(".hpl", "application/x-hpl");
            mimieDic.Add(".hrf", "application/x-hrf");
            mimieDic.Add(".htc", "text/x-component");
            mimieDic.Add(".html", "text/html");
            mimieDic.Add(".htx", "text/html");
            mimieDic.Add(".ico", "image/x-icon");
            mimieDic.Add(".iff", "application/x-iff");
            mimieDic.Add(".igs", "application/x-igs");
            mimieDic.Add(".img", "application/x-img");
            mimieDic.Add(".isp", "application/x-internet-signup");
            mimieDic.Add(".java", "java/*");
            //mimieDic.Add(".jpe", "image/jpeg");
            mimieDic.Add(".jpeg", "image/jpeg");
            //mimieDic.Add(".jpg", "application/x-jpg");
            mimieDic.Add(".jsp", "text/html");
            mimieDic.Add(".lar", "application/x-laplayer-reg");
            mimieDic.Add(".lavs", "audio/x-liquid-secure");
            mimieDic.Add(".lmsff", "audio/x-la-lms");
            mimieDic.Add(".ltr", "application/x-ltr");
            mimieDic.Add(".m2v", "video/x-mpeg");
            mimieDic.Add(".m4e", "video/mpeg4");
            mimieDic.Add(".man", "application/x-troff-man");
            //mimieDic.Add(".mdb", "application/msaccess");
            mimieDic.Add(".mfp", "application/x-shockwave-flash");
            mimieDic.Add(".mhtml", "message/rfc822");
            mimieDic.Add(".mid", "audio/mid");
            mimieDic.Add(".mil", "application/x-mil");
            mimieDic.Add(".mnd", "audio/x-musicnet-download");
            mimieDic.Add(".mocha", "application/x-javascript");
            mimieDic.Add(".mp1", "audio/mp1");
            mimieDic.Add(".mp2v", "video/mpeg");
            mimieDic.Add(".mp4", "video/mpeg4");
            //mimieDic.Add(".mp4", "video/mp4");
            mimieDic.Add(".mpd", "application/vnd.ms-project");
            mimieDic.Add(".mpeg", "video/mpg");
            mimieDic.Add(".mpga", "audio/rn-mpeg");
            mimieDic.Add(".mps", "video/x-mpeg");
            mimieDic.Add(".mpv", "video/mpg");
            mimieDic.Add(".mpw", "application/vnd.ms-project");
            mimieDic.Add(".mtx", "text/xml");
            mimieDic.Add(".net", "image/pnetvue");
            mimieDic.Add(".nws", "message/rfc822");
            mimieDic.Add(".out", "application/x-out");
            mimieDic.Add(".p12", "application/x-pkcs12");
            mimieDic.Add(".p7c", "application/pkcs7-mime");
            mimieDic.Add(".p7r", "application/x-pkcs7-certreqresp");
            mimieDic.Add(".pc5", "application/x-pc5");
            mimieDic.Add(".pcl", "application/x-pcl");
            mimieDic.Add(".pdf", "application/pdf");
            mimieDic.Add(".pdx", "application/vnd.adobe.pdx");
            mimieDic.Add(".pgl", "application/x-pgl");
            mimieDic.Add(".pko", "application/vnd.ms-pki.pko");
            mimieDic.Add(".plg", "text/html");
            mimieDic.Add(".plt", "application/x-plt");
            //mimieDic.Add(".png", "application/x-png");
            mimieDic.Add(".ppa", "application/vnd.ms-powerpoint");
            mimieDic.Add(".pps", "application/vnd.ms-powerpoint");
            //mimieDic.Add(".ppt", "application/x-ppt");
            mimieDic.Add(".prf", "application/pics-rules");
            mimieDic.Add(".prt", "application/x-prt");
            //mimieDic.Add(".ps", "application/postscript");
            mimieDic.Add(".pwz", "application/vnd.ms-powerpoint");
            mimieDic.Add(".ra", "audio/vnd.rn-realaudio");
            mimieDic.Add(".ras", "application/x-ras");
            mimieDic.Add(".rdf", "text/xml");
            mimieDic.Add(".red", "application/x-red");
            mimieDic.Add(".rjs", "application/vnd.rn-realsystem-rjs");
            mimieDic.Add(".rlc", "application/x-rlc");
            mimieDic.Add(".rm", "application/vnd.rn-realmedia");
            mimieDic.Add(".rmi", "audio/mid");
            mimieDic.Add(".rmm", "audio/x-pn-realaudio");
            mimieDic.Add(".rms", "application/vnd.rn-realmedia-secure");
            mimieDic.Add(".rmx", "application/vnd.rn-realsystem-rmx");
            mimieDic.Add(".rp", "image/vnd.rn-realpix");
            mimieDic.Add(".rsml", "application/vnd.rn-rsml");
            //mimieDic.Add(".rtf", "application/msword");
            mimieDic.Add(".rv", "video/vnd.rn-realvideo");
            mimieDic.Add(".sat", "application/x-sat");
            mimieDic.Add(".sdw", "application/x-sdw");
            mimieDic.Add(".slb", "application/x-slb");
            mimieDic.Add(".slk", "drawing/x-slk");
            mimieDic.Add(".smil", "application/smil");
            mimieDic.Add(".snd", "audio/basic");
            mimieDic.Add(".sor", "text/plain");
            mimieDic.Add(".spl", "application/futuresplash");
            mimieDic.Add(".ssm", "application/streamingmedia");
            mimieDic.Add(".stl", "application/vnd.ms-pki.stl");
            mimieDic.Add(".sty", "application/x-sty");
            mimieDic.Add(".swf", "application/x-shockwave-flash");
            mimieDic.Add(".tg4", "application/x-tg4");
            //mimieDic.Add(".tif", "image/tiff");
            mimieDic.Add(".tiff", "image/tiff");
            mimieDic.Add(".top", "drawing/x-top");
            mimieDic.Add(".tsd", "text/xml");
            mimieDic.Add(".uin", "application/x-icq");
            mimieDic.Add(".vcf", "text/x-vcard");
            mimieDic.Add(".vdx", "application/vnd.visio");
            mimieDic.Add(".vpg", "application/x-vpeg005");
            mimieDic.Add(".vsd", "application/x-vsd");
            //mimieDic.Add(".vst", "application/vnd.visio");
            mimieDic.Add(".vsw", "application/vnd.visio");
            mimieDic.Add(".vtx", "application/vnd.visio");
            mimieDic.Add(".wav", "audio/wav");
            mimieDic.Add(".wb1", "application/x-wb1");
            mimieDic.Add(".wb3", "application/x-wb3");
            mimieDic.Add(".wiz", "application/msword");
            mimieDic.Add(".wk4", "application/x-wk4");
            mimieDic.Add(".wks", "application/x-wks");
            mimieDic.Add(".wma", "audio/x-ms-wma");
            mimieDic.Add(".wmf", "application/x-wmf");
            mimieDic.Add(".wmv", "video/x-ms-wmv");
            mimieDic.Add(".wmz", "application/x-ms-wmz");
            mimieDic.Add(".wpd", "application/x-wpd");
            mimieDic.Add(".wpl", "application/vnd.ms-wpl");
            mimieDic.Add(".wr1", "application/x-wr1");
            mimieDic.Add(".wrk", "application/x-wrk");
            mimieDic.Add(".ws2", "application/x-ws");
            mimieDic.Add(".wsdl", "text/xml");
            mimieDic.Add(".xdp", "application/vnd.adobe.xdp");
            mimieDic.Add(".xfd", "application/vnd.adobe.xfd");
            mimieDic.Add(".xhtml", "text/html");
            mimieDic.Add(".xls", "application/x-xls");
            mimieDic.Add(".xml", "text/xml");
            mimieDic.Add(".xq", "text/xml");
            mimieDic.Add(".xquery", "text/xml");
            mimieDic.Add(".xsl", "text/xml");
            mimieDic.Add(".xwd", "application/x-xwd");
            mimieDic.Add(".sis", "application/vnd.symbian.install");
            mimieDic.Add(".x_t", "application/x-x_t");
            mimieDic.Add(".apk", "application/vnd.android.package-archive");
            //mimieDic.Add(".tif", "image/tiff");
            mimieDic.Add("0.301", "application/x-301");
            mimieDic.Add("0.906", "application/x-906");
            mimieDic.Add(".a11", "application/x-a11");
            mimieDic.Add(".ai", "application/postscript");
            mimieDic.Add(".aifc", "audio/aiff");
            mimieDic.Add(".anv", "application/x-anv");
            mimieDic.Add(".asf", "video/x-ms-asf");
            mimieDic.Add(".asx", "video/x-ms-asf");
            mimieDic.Add(".avi", "video/avi");
            mimieDic.Add(".biz", "text/xml");
            mimieDic.Add(".bot", "application/x-bot");
            mimieDic.Add(".c90", "application/x-c90");
            mimieDic.Add(".cat", "application/vnd.ms-pki.seccat");
            mimieDic.Add(".cdr", "application/x-cdr");
            mimieDic.Add(".cer", "application/x-x509-ca-cert");
            mimieDic.Add(".cgm", "application/x-cgm");
            mimieDic.Add(".class", "java/*");
            mimieDic.Add(".cmp", "application/x-cmp");
            mimieDic.Add(".cot", "application/x-cot");
            mimieDic.Add(".crt", "application/x-x509-ca-cert");
            mimieDic.Add(".css", "text/css");
            mimieDic.Add(".dbf", "application/x-dbf");
            mimieDic.Add(".dbx", "application/x-dbx");
            mimieDic.Add(".dcx", "application/x-dcx");
            mimieDic.Add(".dgn", "application/x-dgn");
            mimieDic.Add(".dll", "application/x-msdownload");
            mimieDic.Add(".dot", "application/msword");
            mimieDic.Add(".dtd", "text/xml");
            //mimieDic.Add(".dwf", "application/x-dwf");
            mimieDic.Add(".dxb", "application/x-dxb");
            mimieDic.Add(".edn", "application/vnd.adobe.edn");
            mimieDic.Add(".eml", "message/rfc822");
            mimieDic.Add(".epi", "application/x-epi");
            //mimieDic.Add(".eps", "application/postscript");
            mimieDic.Add(".exe", "application/x-msdownload");
            mimieDic.Add(".fdf", "application/vnd.fdf");
            mimieDic.Add(".fo", "text/xml");
            mimieDic.Add(".g4", "application/x-g4");
            mimieDic.Add(".", "application/x-");
            mimieDic.Add(".gl2", "application/x-gl2");
            mimieDic.Add(".hgl", "application/x-hgl");
            mimieDic.Add(".hpg", "application/x-hpgl");
            mimieDic.Add(".hqx", "application/mac-binhex40");
            mimieDic.Add(".hta", "application/hta");
            mimieDic.Add(".htm", "text/html");
            mimieDic.Add(".htt", "text/webviewhtml");
            mimieDic.Add(".icb", "application/x-icb");
            //mimieDic.Add(".ico", "application/x-ico");
            mimieDic.Add(".ig4", "application/x-g4");
            mimieDic.Add(".iii", "application/x-iphone");
            mimieDic.Add(".ins", "application/x-internet-signup");
            mimieDic.Add(".IVF", "video/x-ivf");
            mimieDic.Add(".jfif", "image/jpeg");
            mimieDic.Add(".jpe", "application/x-jpe");
            mimieDic.Add(".jpg", "image/jpeg");
            mimieDic.Add(".js", "application/x-javascript");
            mimieDic.Add(".la1", "audio/x-liquid-file");
            mimieDic.Add(".latex", "application/x-latex");
            mimieDic.Add(".lbm", "application/x-lbm");
            mimieDic.Add(".ls", "application/x-javascript");
            mimieDic.Add(".m1v", "video/x-mpeg");
            mimieDic.Add(".m3u", "audio/mpegurl");
            mimieDic.Add(".mac", "application/x-mac");
            mimieDic.Add(".math", "text/xml");
            mimieDic.Add(".mdb", "application/x-mdb");
            mimieDic.Add(".mht", "message/rfc822");
            mimieDic.Add(".mi", "application/x-mi");
            mimieDic.Add(".midi", "audio/mid");
            mimieDic.Add(".mml", "text/xml");
            mimieDic.Add(".mns", "audio/x-musicnet-stream");
            mimieDic.Add(".movie", "video/x-sgi-movie");
            mimieDic.Add(".mp2", "audio/mp2");
            //mimieDic.Add(".mp3", "audio/mp3");
            mimieDic.Add(".mp3", "audio/mpeg");
            mimieDic.Add(".mpa", "video/x-mpg");
            mimieDic.Add(".mpe", "video/x-mpeg");
            mimieDic.Add(".mpg", "video/mpg");
            mimieDic.Add(".mpp", "application/vnd.ms-project");
            mimieDic.Add(".mpt", "application/vnd.ms-project");
            mimieDic.Add(".mpv2", "video/mpeg");
            mimieDic.Add(".mpx", "application/vnd.ms-project");
            mimieDic.Add(".mxp", "application/x-mmxp");
            mimieDic.Add(".nrf", "application/x-nrf");
            mimieDic.Add(".odc", "text/x-ms-odc");
            mimieDic.Add(".p10", "application/pkcs10");
            mimieDic.Add(".p7b", "application/x-pkcs7-certificates");
            mimieDic.Add(".p7m", "application/pkcs7-mime");
            mimieDic.Add(".p7s", "application/pkcs7-signature");
            mimieDic.Add(".pci", "application/x-pci");
            mimieDic.Add(".pcx", "application/x-pcx");
            mimieDic.Add(".pfx", "application/x-pkcs12");
            mimieDic.Add(".pic", "application/x-pic");
            mimieDic.Add(".pl", "application/x-perl");
            mimieDic.Add(".pls", "audio/scpls");
            mimieDic.Add(".png", "image/png");
            mimieDic.Add(".pot", "application/vnd.ms-powerpoint");
            mimieDic.Add(".ppm", "application/x-ppm");
            mimieDic.Add(".ppt", "application/vnd.ms-powerpoint");
            mimieDic.Add(".pr", "application/x-pr");
            mimieDic.Add(".prn", "application/x-prn");
            mimieDic.Add(".ps", "application/x-ps");
            mimieDic.Add(".ptn", "application/x-ptn");
            mimieDic.Add(".r3t", "text/vnd.rn-realtext3d");
            mimieDic.Add(".ram", "audio/x-pn-realaudio");
            mimieDic.Add(".rat", "application/rat-file");
            mimieDic.Add(".rec", "application/vnd.rn-recording");
            mimieDic.Add(".rgb", "application/x-rgb");
            mimieDic.Add(".rjt", "application/vnd.rn-realsystem-rjt");
            mimieDic.Add(".rle", "application/x-rle");
            mimieDic.Add(".rmf", "application/vnd.adobe.rmf");
            mimieDic.Add(".rmj", "application/vnd.rn-realsystem-rmj");
            mimieDic.Add(".rmp", "application/vnd.rn-rn_music_package");
            mimieDic.Add(".rmvb", "application/vnd.rn-realmedia-vbr");
            mimieDic.Add(".rnx", "application/vnd.rn-realplayer");
            mimieDic.Add(".rpm", "audio/x-pn-realaudio-plugin");
            mimieDic.Add(".rt", "text/vnd.rn-realtext");
            mimieDic.Add(".rtf", "application/x-rtf");
            mimieDic.Add(".sam", "application/x-sam");
            mimieDic.Add(".sdp", "application/sdp");
            mimieDic.Add(".sit", "application/x-stuffit");
            mimieDic.Add(".sld", "application/x-sld");
            mimieDic.Add(".smi", "application/smil");
            mimieDic.Add(".smk", "application/x-smk");
            mimieDic.Add(".sol", "text/plain");
            mimieDic.Add(".spc", "application/x-pkcs7-certificates");
            mimieDic.Add(".spp", "text/xml");
            mimieDic.Add(".sst", "application/vnd.ms-pki.certstore");
            mimieDic.Add(".stm", "text/html");
            mimieDic.Add(".svg", "text/xml");
            mimieDic.Add(".tdf", "application/x-tdf");
            mimieDic.Add(".tga", "application/x-tga");
            mimieDic.Add(".tif", "application/x-tif");
            mimieDic.Add(".tld", "text/xml");
            mimieDic.Add(".torrent", "application/x-bittorrent");
            mimieDic.Add(".txt", "text/plain");
            mimieDic.Add(".uls", "text/iuls");
            mimieDic.Add(".vda", "application/x-vda");
            mimieDic.Add(".vml", "text/xml");
            //mimieDic.Add(".vsd", "application/vnd.visio");
            mimieDic.Add(".vss", "application/vnd.visio");
            mimieDic.Add(".vst", "application/x-vst");
            mimieDic.Add(".vsx", "application/vnd.visio");
            mimieDic.Add(".vxml", "text/xml");
            mimieDic.Add(".wax", "audio/x-ms-wax");
            mimieDic.Add(".wb2", "application/x-wb2");
            mimieDic.Add(".wbmp", "image/vnd.wap.wbmp");
            mimieDic.Add(".wk3", "application/x-wk3");
            mimieDic.Add(".wkq", "application/x-wkq");
            mimieDic.Add(".wm", "video/x-ms-wm");
            mimieDic.Add(".wmd", "application/x-ms-wmd");
            mimieDic.Add(".wml", "text/vnd.wap.wml");
            mimieDic.Add(".wmx", "video/x-ms-wmx");
            mimieDic.Add(".wp6", "application/x-wp6");
            mimieDic.Add(".wpg", "application/x-wpg");
            mimieDic.Add(".wq1", "application/x-wq1");
            mimieDic.Add(".wri", "application/x-wri");
            mimieDic.Add(".ws", "application/x-ws");
            mimieDic.Add(".wsc", "text/scriptlet");
            mimieDic.Add(".wvx", "video/x-ms-wvx");
            mimieDic.Add(".xdr", "text/xml");
            mimieDic.Add(".xfdf", "application/vnd.adobe.xfdf");
            //mimieDic.Add(".xls", "application/vnd.ms-excel");
            mimieDic.Add(".xlw", "application/x-xlw");
            mimieDic.Add(".xpl", "audio/scpls");
            mimieDic.Add(".xql", "text/xml");
            mimieDic.Add(".xsd", "text/xml");
            mimieDic.Add(".xslt", "text/xml");
            mimieDic.Add(".x_b", "application/x-x_b");
            mimieDic.Add(".sisx", "application/vnd.symbian.install");
            mimieDic.Add(".ipa", "application/vnd.iphone");
            mimieDic.Add(".xap", "application/x-silverlight-app");

            mimieDic.Add(".mkv", "video/x-matroska");

            //HttpContentTypes.Clear();
            //foreach (var kv in mimieDic)
            //{
            //    HttpContentTypes.AddMimeMapping(kv.Key, kv.Value);
            //}
        }

        #endregion


        #region Test Client Request

        private static readonly string baseUrl = "http://127.0.0.1:8080/";

        #region TestClient

        public static void TestCallApi()
        {
            HttpClient httpClient = new HttpClient();
            httpClient.Timeout = TimeSpan.FromSeconds(300);

            //for (int i = 0; i < 7; i++)
            //{
            //    TestCallGetApi(httpClient, i);
            //}


            //for (int i = 0; i < 2; i++)
            //{
            //    TestCallPostApi(httpClient, i);
            //}

            //for (int i = 0; i < 2; i++)
            //{
            //    TestCallPutApi(httpClient, i);
            //}

            //for (int i = 0; i < 2; i++)
            //{
            //    TestCallDeletApi(httpClient, i);
            //}

            TestCallUploadFileApi(httpClient);
            TestCallDownloadFileApi(httpClient);
        }

        private static void TestCallDownloadFileApi(HttpClient httpClient)
        {
            string url = baseUrl + "李志辉-紫禁花园.mp3";
            url = baseUrl + "暴走财神.2019.HD1080P.国语中字.mp4";
            string filePath = Path.Combine(@"D:\tmp\utilzd", Path.GetFileName(url));

            using (Stream stream = httpClient.GetStreamAsync(url).Result)
            {
                using (var fs = File.Create(filePath))
                {
                    stream.CopyTo(fs);
                }
            }
        }


        private static void TestCallUploadFileApi(HttpClient httpClient)
        {
            string url = baseUrl + "testApi/uploadFile";
            string filePath = @"D:\Music\Se7en La la la ( Remix ).mp3";
            using (var fs = File.OpenRead(filePath))
            {
                var content = new MultipartFormDataContent();
                content.Add(new StreamContent(fs), "file", Path.GetFileName(filePath));
                Task<HttpResponseMessage> task = httpClient.PostAsync(url, content);
                Console.WriteLine($"uploadFile {task.Result.StatusCode}");

                Task<string> tt = task.Result.Content.ReadAsStringAsync();
                Console.WriteLine($"uploadFile {tt.Result}");
            }
        }


        private static void TestCallDeletApi(HttpClient httpClient, int index)
        {
            string url;
            switch (index)
            {
                case 0:
                    url = baseUrl + "testApi/Delete?id=111";
                    break;
                case 1:
                    url = baseUrl + "testApi/delete2?id=222";
                    break;
                default:
                    Console.WriteLine($"未知的索引{index}");
                    return;
            }

            Task<HttpResponseMessage> task = httpClient.DeleteAsync(url);
            Console.WriteLine($"{index} {task.Result.StatusCode}");

            Task<string> tt = task.Result.Content.ReadAsStringAsync();
            Console.WriteLine($"{index} {tt.Result}");
        }

        private static void TestCallPutApi(HttpClient httpClient, int index)
        {
            string url;
            switch (index)
            {
                case 0:
                    url = baseUrl + "testApi";
                    break;
                case 1:
                    url = baseUrl + "testApi?id=234";
                    break;
                default:
                    Console.WriteLine($"未知的索引{index}");
                    return;
            }

            StuInfo stuInfo = new StuInfo()
            {
                Id = 1232,
                Age = 182,
                Name = "yf夜风2"
            };
            var opt = new System.Text.Json.JsonSerializerOptions()
            {
                //PropertyNameCaseInsensitive = false,
                PropertyNamingPolicy = new SystemTextJsonNameFirstCharToLower()
            };
            var json = System.Text.Json.JsonSerializer.Serialize(stuInfo, opt);
            //HttpContent content = System.Net.Http.Json.JsonContent.Create(stuInfo, null, opt);
            HttpContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
            Task<HttpResponseMessage> task = httpClient.PutAsync(url, content);
            Console.WriteLine($"{index} {task.Result.StatusCode}");

            Task<string> tt = task.Result.Content.ReadAsStringAsync();
            Console.WriteLine($"{index} {tt.Result}");
        }

        private static void TestCallPostApi(HttpClient httpClient, int index)
        {
            string url;
            switch (index)
            {
                case 0:
                    url = baseUrl + "testApi";
                    break;
                case 1:
                    url = baseUrl + "testApi/test?min=123&max=465";
                    break;
                default:
                    Console.WriteLine($"未知的索引{index}");
                    return;
            }

            StuInfo stuInfo = new StuInfo()
            {
                Id = 123,
                Age = 18,
                Name = "yf夜风"
            };
            var opt = new System.Text.Json.JsonSerializerOptions()
            {
                //PropertyNameCaseInsensitive = false,
                PropertyNamingPolicy = new SystemTextJsonNameFirstCharToLower()
            };
            var json = System.Text.Json.JsonSerializer.Serialize(stuInfo, opt);
            //HttpContent content = System.Net.Http.Json.JsonContent.Create(stuInfo, null, opt);
            HttpContent content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
            Task<HttpResponseMessage> task = httpClient.PostAsync(url, content);
            Console.WriteLine($"{index} {task.Result.StatusCode}");

            Task<string> tt = task.Result.Content.ReadAsStringAsync();
            Console.WriteLine($"{index} {tt.Result}");
        }


        private static void TestCallGetApi(HttpClient httpClient, int index)
        {
            string url;
            switch (index)
            {
                case 0:
                    url = baseUrl + "testApi";
                    break;
                case 1:
                    url = baseUrl + "testApi/getName";
                    break;
                case 2:
                    url = baseUrl + "testApi/test?min=123&max=456";
                    break;
                case 3:
                    url = baseUrl + "testApi/6/10/50.png";
                    break;
                case 4:
                    url = baseUrl + "testApi/abc6/gg10mm/kk/50.png";
                    break;
                case 5:
                    url = baseUrl + "testApi/123夜风.dat";
                    break;
                case 6:
                    url = baseUrl + "testApi/mix/3/gg2mm/kk/1.png?min=132&max=456";
                    break;
                default:
                    Console.WriteLine($"未知的索引{index}");
                    return;
            }

            Task<string> task = httpClient.GetStringAsync(url);
            Console.WriteLine($"{index} {task.Result}");
        }

        #endregion


        #region TestHttpRequest
        public static void TestCallApi2()
        {
            int timeout = 30000;
            //for (int i = 0; i < 7; i++)
            //{
            //    TestHttpRequestCallGetApi(i, timeout);
            //}

            //for (int i = 0; i < 2; i++)
            //{
            //    TestHttpRequestCallPostApi(i, timeout);
            //}

            //for (int i = 0; i < 2; i++)
            //{
            //    TestHttpRequestCallPutApi(i, timeout);
            //}

            //for (int i = 0; i < 2; i++)
            //{
            //    TestHttpRequestCallDeletApi(i, timeout);
            //}

            TestHttpRequestCallUploadFileApi(timeout);
            //TestHttpRequestDownloadFile(timeout);
        }


        private static void TestHttpRequestDownloadFile(int timeout)
        {
            try
            {
                string url = baseUrl + "李志辉-紫禁花园.mp3";
                url = baseUrl + "暴走财神.2019.HD1080P.国语中字.mp4";
                string filePath = Path.Combine(@"D:\tmp\utilzd", Path.GetFileName(url));

                string fileName = Path.GetFileName(url);
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }

                using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                {
                    // 设置参数
                    HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
                    //发送请求并获取相应回应数据
                    HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                    //直到request.GetResponse()程序才开始向目标网页发送Post请求
                    using (Stream responseStream = response.GetResponseStream())
                    {
                        //创建本地文件写入流
                        byte[] bArr = new byte[1024];
                        int iTotalSize = 0;
                        int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                        while (size > 0)
                        {
                            iTotalSize += size;
                            fs.Write(bArr, 0, size);
                            size = responseStream.Read(bArr, 0, (int)bArr.Length);
                        }
                    }
                }

                Console.WriteLine($"downloadFile end");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"downloadFile fail," + ex.Message);
            }
        }


        private static void TestHttpRequestCallUploadFileApi(int timeout)
        {
            string url = baseUrl + "testApi/uploadFile";
            string filePath = @"D:\tmp\utilzd\李志辉-紫禁花园.mp3";
            //filePath = @"D:\tmp\utilzd\暴走财神.2019.HD1080P.国语中字.mp4";
            string ret = HttpUploadFile(url, new string[] { filePath, @"D:\tmp\utilzd\极域课程管理系统软件V6.0_2016豪华版.zip" });
            Console.WriteLine(ret);
        }

        /// <summary>
        /// HttpUploadFile
        /// </summary>
        /// <param name="url"></param>
        /// <param name="files"></param>
        /// <param name="data"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        private static string HttpUploadFile(string url, string[] files)
        {
            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endbytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");

            //1.HttpWebRequest
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.ContentType = "multipart/form-data; boundary=" + boundary;
            request.Method = "POST";
            request.KeepAlive = true;
            request.Credentials = CredentialCache.DefaultCredentials;

            using (Stream stream = request.GetRequestStream())
            {
                //1.2 file
                string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";
                byte[] buffer = new byte[4096];
                int bytesRead = 0;
                for (int i = 0; i < files.Length; i++)
                {
                    stream.Write(boundarybytes, 0, boundarybytes.Length);
                    string header = string.Format(headerTemplate, "file" + i, Path.GetFileName(files[i]));
                    byte[] headerbytes = Encoding.UTF8.GetBytes(header);
                    stream.Write(headerbytes, 0, headerbytes.Length);
                    using (FileStream fileStream = new FileStream(files[i], FileMode.Open, FileAccess.Read))
                    {
                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            stream.Write(buffer, 0, bytesRead);
                        }
                    }
                }

                //1.3 form end
                stream.Write(endbytes, 0, endbytes.Length);
            }

            //2.WebResponse
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader stream = new StreamReader(response.GetResponseStream()))
            {
                return stream.ReadToEnd();
            }
        }




        private static void TestHttpRequestCallDeletApi(int index, int timeout)
        {
            string url;
            switch (index)
            {
                case 0:
                    url = baseUrl + "testApi/Delete?id=111";
                    break;
                case 1:
                    url = baseUrl + "testApi/delete2?id=222";
                    break;
                default:
                    Console.WriteLine($"未知的索引{index}");
                    return;
            }

            HttpWebRequest request = WebRequest.CreateHttp(url);
            request.Timeout = timeout;
            request.Method = UtilZ.Dotnet.Ex.Communication.Net.Web.HttpRequestMethods.DELETE;

            WebResponse response = request.GetResponse();
            using (var stream = response.GetResponseStream())
            {
                var reader = new StreamReader(stream, Encoding.UTF8);
                string str = reader.ReadToEnd();
                Console.WriteLine($"{index} {str}");
            }
        }

        private static void TestHttpRequestCallPutApi(int index, int timeout)
        {
            string url;
            switch (index)
            {
                case 0:
                    url = baseUrl + "testApi";
                    break;
                case 1:
                    url = baseUrl + "testApi?id=234";
                    break;
                default:
                    Console.WriteLine($"未知的索引{index}");
                    return;
            }

            StuInfo stuInfo = new StuInfo()
            {
                Id = 1232,
                Age = 182,
                Name = "yf夜风2"
            };
            var json = UtilZ.Dotnet.Ex.Json.JsonSerializer.SerializeObject(stuInfo);

            HttpWebRequest request = WebRequest.CreateHttp(url);
            request.Timeout = timeout;
            request.Method = WebRequestMethods.Http.Put;
            request.ContentType = "application/json";

            byte[] postData = Encoding.UTF8.GetBytes(json);
            request.ContentLength = postData.Length;
            using (var reqStream = request.GetRequestStream())
            {
                reqStream.Write(postData, 0, postData.Length);
            }

            WebResponse response = request.GetResponse();
            using (var stream = response.GetResponseStream())
            {
                var reader = new StreamReader(stream, Encoding.UTF8);
                string str = reader.ReadToEnd();
                Console.WriteLine($"{index} {str}");
            }
        }

        private static void TestHttpRequestCallPostApi(int index, int timeout)
        {
            string url;
            switch (index)
            {
                case 0:
                    url = baseUrl + "testApi";
                    break;
                case 1:
                    url = baseUrl + "testApi/test?min=123&max=465";
                    break;
                default:
                    Console.WriteLine($"未知的索引{index}");
                    return;
            }

            StuInfo stuInfo = new StuInfo()
            {
                Id = 123,
                Age = 18,
                Name = "yf夜风"
            };
            var json = UtilZ.Dotnet.Ex.Json.JsonSerializer.SerializeObject(stuInfo);

            HttpWebRequest request = WebRequest.CreateHttp(url);
            request.Timeout = timeout;
            request.Method = WebRequestMethods.Http.Post;
            request.ContentType = "application/json";

            byte[] postData = Encoding.UTF8.GetBytes(json);
            request.ContentLength = postData.Length;
            using (var reqStream = request.GetRequestStream())
            {
                reqStream.Write(postData, 0, postData.Length);
            }

            WebResponse response = request.GetResponse();
            using (var stream = response.GetResponseStream())
            {
                var reader = new StreamReader(stream, Encoding.UTF8);
                string str = reader.ReadToEnd();
                Console.WriteLine($"{index} {str}");
            }
        }

        private static void TestHttpRequestCallGetApi(int index, int timeout)
        {
            string url;
            switch (index)
            {
                case 0:
                    url = baseUrl + "testApi";
                    break;
                case 1:
                    url = baseUrl + "testApi/getName";
                    break;
                case 2:
                    url = baseUrl + "testApi/test?min=123&max=456";
                    break;
                case 3:
                    url = baseUrl + "testApi/6/10/50.png";
                    break;
                case 4:
                    url = baseUrl + "testApi/abc6/gg10mm/kk/50.png";
                    break;
                case 5:
                    url = baseUrl + "testApi/123夜风.dat";
                    break;
                case 6:
                    url = baseUrl + "testApi/mix/3/gg2mm/kk/1.png?min=132&max=456";
                    break;
                default:
                    Console.WriteLine($"未知的索引{index}");
                    return;
            }

            HttpWebRequest request = WebRequest.CreateHttp(url);
            request.Timeout = timeout;
            request.Method = WebRequestMethods.Http.Get;
            WebResponse response = request.GetResponse();
            using (var stream = response.GetResponseStream())
            {
                var reader = new StreamReader(stream, Encoding.UTF8);
                string str = reader.ReadToEnd();
                Console.WriteLine($"{index} {str}");
            }

        }
        #endregion

        #endregion
    }


    internal class DynamicTileApi : IDynamicApi
    {

        public DynamicTileApi()
        {

        }

        /// <summary>
        /// 获取api函数信息集合
        /// </summary>
        /// <returns></returns>
        public IEnumerable<DynamicApiInfo> GetWebApiInfos()
        {
            string urlPre = @"api/v1/gis/ts1";

            //http://127.0.0.1:23018/api/v1/gis/ts1?z=5&x=24&y=13
            var apiInfo1 = new DynamicApiInfo(HttpRequestMethods.GET, nameof(DynamicTileApi.GetTileApi), urlPre + "?z={z}&x={x}&y={y}");

            //http://127.0.0.1:23018/api/v1/gis/ts1
            var apiInfo2 = new DynamicApiInfo(HttpRequestMethods.GET, nameof(DynamicTileApi.GetZoomRangeApi), urlPre + "/zoomrange");

            return new DynamicApiInfo[] { apiInfo1, apiInfo2 };

            //return new DynamicApiInfo[]
            //{
            //    //http://127.0.0.1:23018/api/v1/gis/ts1?z=5&x=24&y=13
            //    new DynamicApiInfo(HttpRequestMethods.GET,nameof(DynamicTileApi.GetTileApi), urlPre + "?z={z}&x={x}&y={y}"),

            //    //http://127.0.0.1:23018/api/v1/gis/ts1
            //    new DynamicApiInfo(HttpRequestMethods.GET,nameof(DynamicTileApi.GetZoomRangeApi), urlPre + "/zoomrange"),
            //};
        }



        public ApiResult GetZoomRangeApi()
        {
            try
            {
                ZRange range = new ZRange(1, 20);
                return new ApiResult(ApiResultStatus.Succes, JsonSerializer.SerializeObject(range));
            }
            catch (Exception ex)
            {
                Loger.Warn(ex, $"缩放层级范围请求异常.");
                return new ApiResult(ApiResultStatus.Exception, ex.Message);
            }

        }

        /// <summary>
        /// API函数
        /// </summary>
        /// <param name="z"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        //[HttpGet("ts2?z={z}&x={x}&y={y}")]
        public IApiActionResult GetTileApi(int z, int x, int y)
        {
            try
            {
                byte[] buffer = new byte[10];
                for (int i = 0; i < buffer.Length; i++)
                {
                    buffer[i] = (byte)i;
                }

                if (buffer == null)
                {
                    return new ApiBadRequest();
                }

                return new ApiBufferDataResult()
                {
                    Data = new DataSource(buffer),
                    ContentType = "image/png"
                };
            }
            catch (Exception ex)
            {
                Loger.Error(ex, $"请求tile异常。z:{z},x:{x},y:{y}");
                return new ApiBadRequest();
            }
        }


    }

    /// <summary>
    /// Z范围
    /// </summary>
    public struct ZRange
    {
        /// <summary>
        /// Z最小值
        /// </summary>
        public readonly byte Min;

        /// <summary>
        /// Z最大值
        /// </summary>
        public readonly byte Max;


        /// <summary>
        /// 构造函数初始化
        /// </summary>
        /// <param name="min">Z最小值</param>
        /// <param name="max">Z最大值</param>
        public ZRange(byte min, byte max)
        {
            this.Min = min;
            this.Max = max;
        }
    }

    internal class TestDynamicApi : IDynamicApi
    {
        public TestDynamicApi()
        {

        }


        /// <summary>
        /// 获取api函数信息集合
        /// </summary>
        /// <returns></returns>
        IEnumerable<DynamicApiInfo> IDynamicApi.GetWebApiInfos()
        {
            return new DynamicApiInfo[]
            {
                //http://127.0.0.1:8080/test1?min=100&max=200
                new DynamicApiInfo(HttpRequestMethods.GET,nameof(TestDynamicApi.MapApiCallback), "/test1?min={min}&max={max}"),

                //http://127.0.0.1:8080/test2?min=100&max=200
                new DynamicApiInfo(HttpRequestMethods.GET,nameof(TestDynamicApi.MapApiCallback2), "/test2?min={min}&max={max}"),

                //http://127.0.0.1:8080/test3?min=100&max=200
                new DynamicApiInfo(HttpRequestMethods.GET,this.GetType().GetMethod( nameof(TestDynamicApi.MapApiCallback2)), "/test3?min={min}&max={max}"),
            };
        }

        /// <summary>
        /// web API函数
        /// </summary>
        /// <param name="args">参数</param>
        /// <returns>返回值</returns>
        public object MapApiCallback(int min, int max)
        {
            Loger.Info($"ApiMapCallback min:{min},max:{max}");
            return $"ok_{TimeEx.GetTimestamp()}";
        }

        /// <summary>
        /// web API函数
        /// </summary>
        /// <param name="args">参数</param>
        /// <returns>返回值</returns>
        public object MapApiCallback2(int min, int max)
        {
            Loger.Info($"ApiMapCallback min:{min},max:{max}");
            return $"ok_{TimeEx.GetTimestamp()}";
        }

    }

    internal class SystemTextJsonNameFirstCharToLower : System.Text.Json.JsonNamingPolicy
    {
        public SystemTextJsonNameFirstCharToLower()
        {

        }

        public override string ConvertName(string name)
        {
            if (char.IsUpper(name[0]))
            {
                char ch = char.ToLower(name[0]);
                name = $"{ch}{name.Substring(1)}";
            }

            return name;
        }
    }


    internal class TestRequestMiddleware : MiddlewareAbs
    {

        public TestRequestMiddleware()
        {

        }

        protected override bool PrimitiveTryInvoke(HttpRequest request, out IHttpResponse response)
        {
            bool result = false;
            response = null;
            switch (request.Method)
            {
                case HttpRequestMethods.GET:

                    break;
                case HttpRequestMethods.POST:
                    response = this.Post(request);
                    result = true;
                    break;
                case HttpRequestMethods.PUT:
                    break;
                case HttpRequestMethods.DELETE:
                    break;
                case HttpRequestMethods.EXTENSION_MOTHED:
                    break;
                default:
                    break;
            }

            return result;
        }

        private IHttpResponse Post(HttpRequest request)
        {
            string contentType = request.Headers[HttpRequestHeaders.ContentType];
            string json = request.GetBody();
            Loger.Info($"收到{request.Url} POST 数据:\r\n{json}");

            var res = new HttpResponse(request.Connection);
            res.TextEncoding = request.GetClientTextEncoding();
            //res.SetText($"Post Succes {TimeEx.GetTimestamp()}");
            string filePath = @"D:\Projects\Posture\功能指标.txt";
            string text = File.ReadAllText(filePath);
            res.SetText(text);
            res.ChunkSize = 1024;

            return res;
        }
    }

    [Route("api/v1/tiles")]
    public class GISTileFileApi
    {
        private readonly string _tileFilePathRootDir;

        public GISTileFileApi()
        {
            //this._tileFilePathRootDir = @"I:\osm\domTiles";
            this._tileFilePathRootDir = @"I:\osm\domTiles2";
            this._tileFilePathRootDir = @"D:\tmp\tile10";
        }

        [HttpGet("{z}/{x}/{y}.png")]
        public IApiActionResult Get(int z, int x, int y)
        {
            try
            {
                string tileFilePath = $@"{this._tileFilePathRootDir}\{z}\{x}\{y}.png";
                if (File.Exists(tileFilePath))
                {
                    byte[] buffer = File.ReadAllBytes(tileFilePath);
                    return new ApiBufferDataResult()
                    {
                        Data = new DataSource(buffer),
                        ContentType = "image/png"
                    };
                }
                else
                {
                    return new ApiBadRequest();
                }
            }
            catch (Exception ex)
            {
                string err = $"请求tile异常。z:{z},x:{x},y:{y}";
                Loger.Error(ex, err);
                return new ApiBadRequest();
            }
        }
    }

    [Route("testApi")]
    internal class TestApi
    {
        private readonly SessionManagerMiddleware _smm;
        public TestApi(SessionManagerMiddleware smm)
        {
            this._smm = smm;
        }

        [HttpGet("testNoVoid")]
        public void Test(HttpActionContext contextData)
        {

        }


        //http://192.168.10.96:23018/testApi
        [HttpGet]
        public ApiResult Get()
        {
            Loger.Info($"Get-收到无参数请求");
            return new ApiResult(ApiResultStatus.Succes, $"Get ok-{TimeEx.GetTimestamp()}");
        }

        //http://192.168.10.96:23018/testApi/getName
        [HttpGet("getName")]
        public ApiResult GetName()
        {
            Loger.Info($"GetName-收到无参数请求");
            return new ApiResult(ApiResultStatus.Succes, $"getName ok-{TimeEx.GetTimestamp()}");
        }

        //http://192.168.10.96:23018/testApi/test?min=123&max=456
        [Description("好多参数的api")]
        [HttpGet("test?min={timestampMin}&max={timestampMax}")]
        public ApiResult Get([Description("时间戳最小值")] long timestampMin, [Description("时间戳最大值")] long timestampMax)
        {
            Loger.Info($"Get-收到模板参数请求");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }


        //http://192.168.10.96:23018/testApi/{z}/{x}/{y}.png
        [HttpGet("{z}/{x}/{y}.png")]
        public ApiResult Get(int z, int x, int y)
        {
            string data = $"{z}-{x}-{y} ok-{TimeEx.GetTimestamp()}";
            Loger.Info($"Get-url参数模板:{data}");
            return new ApiResult(ApiResultStatus.Succes, data);
        }

        //http://192.168.10.96:23018/testApi/{z}/{x}/{y}.png
        [HttpGet("abc{z}/gg{x}mm/kk/{y}.png")]
        public ApiResult Get2(int z, int x, int y, HttpActionContext actionContext)
        {
            string data = $"{z}-{x}-{y} ok-{TimeEx.GetTimestamp()}";
            Loger.Info($"Get-url参数模板:{data}");
            return new ApiResult(ApiResultStatus.Succes, data);
        }

        //http://192.168.10.96:23018/testApi?qwe.dat
        [HttpGet("{fileName}")]
        public ApiResult GetXX(string fileName)
        {
            Loger.Info($"Get-收到无参数请求");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }

        //http://192.168.10.96:23018/testApi/mid/{z}/gg{x}mm/kk/{y}.png?min={timestampMin}&max={timestampMax}
        [HttpGet("mix/{z}/gg{x}mm/kk/{y}.png?min={timestampMin}&max={timestampMax}")]
        public ApiResult Mix([Description("时间戳最小值")] long timestampMin, [Description("时间戳最大值")] long timestampMax, int z, int x, int y, HttpActionContext actionContext)
        {
            string data = $"时间范围:{timestampMin}-{timestampMax},层级{z}-{x}-{y} ok-{TimeEx.GetTimestamp()}";
            Loger.Info($"Mix参数模板:{data}");
            return new ApiResult(ApiResultStatus.Succes, data);
        }





        //http://192.168.10.96:23018/testApi
        [HttpPost]
        public ApiResult Post([FromBody] StuInfo stuInfo)
        {
            Loger.Info($"收到数据:\r\n{stuInfo.ToString()}");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }


        //http://192.168.10.96:23018/testApi
        [HttpPost("test?min={timestampMin}&max={timestampMax}")]
        //[HttpPost("test?timestampMin={timestampMin}&timestampMax={timestampMax}")]
        public ApiResult Post(long timestampMin, long timestampMax, [FromBody] StuInfo stuInfo, HttpActionContext actionContext)
        {
            Loger.Info($"收到数据:\r\n{stuInfo.ToString()}");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }






        //http://192.168.10.96:23018/testApi
        [HttpPost("uploadFile")]
        public ApiResult UploadFile([FromBody] HttpFormData formData)
        {
            //Loger.Info($"收到上传文件数据:\r\n");
            string filePath;
            foreach (var file in formData.Files)
            {
                if (string.IsNullOrWhiteSpace(file.Filename))
                {
                    filePath = Path.Combine("imgs", $"{Guid.NewGuid().ToString()}.dat");
                }
                else
                {
                    filePath = Path.Combine("imgs", $"{file.Filename}");
                }

                DirectoryInfoEx.CheckFilePathDirectory(filePath);
                using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                {
                    file.CopyTo(fs);
                }
            }
            Loger.Info($"收到上传文件数据:\r\n");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }








        //http://192.168.10.96:23018/testApi
        [HttpPut]
        public ApiResult Put([FromBody] StuInfo stuInfo)
        {
            Loger.Info($"Put-收到数据:\r\n{stuInfo.ToString()}");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }


        //http://192.168.10.96:23018/testApi?id=13
        [HttpPut("id={id}")]
        public ApiResult Put(int id, HttpActionContext actionContext, [FromBody] StuInfo stuInfo)
        {
            Loger.Info($"Put-收到数据:\r\n{stuInfo.ToString()}");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }






        //http://192.168.10.96:23018/testApi?id=111
        [HttpDelete]
        public ApiResult Delete(long id, HttpActionContext actionContext)
        {
            Loger.Info($"Delete-收到删除主键:{id}");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }

        //http://192.168.10.96:23018/testApi?id=111
        [HttpDelete("delete2?id={id}")]
        public ApiResult Delete2(long id)
        {
            Loger.Info($"Delete-收到删除主键:{id}");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }








        //http://192.168.10.96:23018/testApi
        [HttpExtensionMethod]
        public ApiResult Extension([FromBody] StuInfo stuInfo)
        {
            Loger.Info($"收到数据:\r\n{stuInfo.ToString()}");
            return new ApiResult(ApiResultStatus.Succes, $"ok-{TimeEx.GetTimestamp()}");
        }





        //http://192.168.10.96:23018/testApi/login?uid=yf&pwd=qwe123
        [Description("登录")]
        [HttpGet("login?uid={uid}&pwd={pwd}")]
        public ApiResult Login(string uid, string pwd, HttpActionContext actionContext)
        {
            string cookie = $"{uid}_{pwd}".GetHashCode().ToString();
            this._smm.SetCookie(cookie, new HttpSession(uid, pwd));
            actionContext.Response.AddHeader(HttpResponseHeaders.SetCookie, cookie);
            Loger.Info($"Login");
            return new ApiResult(ApiResultStatus.Succes, cookie);
        }

        //http://192.168.10.96:23018/testApi/getAuthData?id=23
        [Description("获取需要登录的数据")]
        [HttpGet("getAuthData?id={id}")]
        public ApiResult GetAuthData(int id, HttpActionContext actionContext)
        {
            if (actionContext.Request.Session == null)
            {
                Loger.Info("GetAuthData失败,没有会话");
                return new ApiResult(ApiResultStatus.AuthFail, "cookie无效");
            }
            else
            {
                Loger.Info("GetAuthData成功");
                //actionContext.Response.AddHeader(HttpResponseHeaders.SetCookie, cookie);
                return new ApiResult(ApiResultStatus.Succes, "GetAuthData成功");
            }
        }



    }

    /// <summary>
    /// http会话接口
    /// </summary>
    public class HttpSession : IHttpSession
    {
        public string UID { get; private set; }

        public string PWD { get; private set; }


        public HttpSession(string uid, string pwd)
        {
            this.UID = uid;
            this.PWD = pwd;
        }




        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }
    }


    public class StuInfo
    {
        //private static JsonSerializerSettings _jsonSerializerSetting = null;
        //public static JsonSerializerSettings JsonSerializerSetting
        //{
        //    get { return _jsonSerializerSetting; }
        //}

        //static StuInfo()
        //{
        //    _jsonSerializerSetting = new JsonSerializerSettings()
        //    {
        //        ContractResolver = new CamelCasePropertyNamesContractResolver()
        //    };
        //}


        public int Id { get; set; }

        public string Name { get; set; }

        public int Age { get; set; }



        public StuInfo()
        {

        }



        public override string ToString()
        {
            return $"ID:{Id}    Name:{Name}   Age: {Age}";
        }


    }

    public class TestSerializer : WebSerializerAbs
    {
        public TestSerializer()
        {

        }


        /// <summary>
        /// 将对象序列化为xml
        /// </summary>
        /// <param name="obj">要序列化的对象</param>
        /// <returns>xml</returns>
        protected override string PrimitiveXmlSerialize(object obj)
        {
            return SerializeEx.XmlSerializer(obj);
        }

        /// <summary>
        /// 将xml反序列化为指定类型的对象
        /// </summary>
        /// <param name="xml">xml</param>
        /// <param name="targetType">目标类型</param>
        /// <returns>结果对象</returns>
        protected override object PrimitiveXmlDeserialize(string xml, Type targetType)
        {
            return SerializeEx.XmlDeserializerFromString(xml, targetType);
        }

        /// <summary>
        /// 将对象序列化为json
        /// </summary>
        /// <param name="obj">要序列化的对象</param>
        /// <returns>json</returns>
        protected override string PrimitiveJsonSerialize(object obj)
        {
            //new System.Text.Json.Serialization.Metadata.JsonTypeInfo()
            return System.Text.Json.JsonSerializer.Serialize(obj);
            //return JsonConvert.SerializeObject(obj, StuInfo.JsonSerializerSetting);
        }

        /// <summary>
        /// 将json反序列化为指定类型的对象
        /// </summary>
        /// <param name="json">json</param>
        /// <param name="targetType">目标类型</param>
        /// <returns>结果对象</returns>
        protected override object PrimitiveJsonDeserialize(string json, Type targetType)
        {
            //return JsonConvert.DeserializeObject(json, targetType, StuInfo.JsonSerializerSetting);
            return System.Text.Json.JsonSerializer.Deserialize(json, targetType);
        }


    }

    internal class WebSiteFileProvider : IWebSiteResourceProvider
    {
        public WebSiteFileProvider()
        {

        }

        /// <summary>
        /// 尝试获取站点资源，获取成功返回true[此时输出的资源文件路径和响应二选一，且响应优先级更高],获取失败返回false
        /// </summary>
        /// <param name="webSiteConfig">web站点配置</param>
        /// <param name="request">http请求</param>
        /// <param name="resourceFilePath">获取成功时的资源文件路径</param>
        /// <param name="response">获取成功时的响应,当响应不为null时直接使用此值响应输出</param>
        /// <returns>获取成功返回true,获取失败返回false</returns>
        public bool TryGetResource(WebSiteConfig webSiteConfig, HttpRequest request, out string resourceFilePath, out IHttpResponse response)
        {
            string userAgent;
            if (request.Headers.TryGetValue(HttpRequestHeaders.UserAgent, out userAgent))
            {
                if (userAgent.Contains("MSIE", StringComparison.OrdinalIgnoreCase))
                {
                    Loger.Info("IE浏览器发起的请求");
                }
                else
                {
                    Loger.Info("非IE浏览器发起的请求");
                }
            }

            resourceFilePath = null;
            response = null;
            return false;
        }
    }
}
